//#include "stdafx.h"
#include "JuliaBrain.h"

JuliaBrain::JuliaBrain(void) :
		m_pTrainingCaseDB(NULL) {
	JuliaChainDefine* pDefine;
	for (int m = 0; m < NERVUS_CHAIN_COUNT; m++) {
		pDefine = m_chDefine + NERVUS_SIGNAL_COUNT * m;
		pDefine[0].MakeStaticChain(NERVUS_COUNT);
		for (int i = 1; i < NERVUS_SIGNAL_COUNT; i++)
			pDefine[i].MakeEmptyChain(NERVUS_COUNT, 3);
	}

	m_nCurrentChangedChain = 0;
}

JuliaBrain::~JuliaBrain(void) {
}

void JuliaBrain::BuildNervusChain(int nIdx, Complex def) {
	m_nArray[nIdx] = new NervusChainArray(def);

	JuliaChainDefine* pDefine;
	for (int m = 0; m < NERVUS_CHAIN_COUNT; m++) {
		pDefine = m_chDefine + NERVUS_SIGNAL_COUNT * m;
		for (int i = 0; i < NERVUS_SIGNAL_COUNT; i++)
			m_nArray[nIdx]->SetChainParam(m, i, pDefine[i]);
	}
}

void JuliaBrain::ReleaseNervusChain(int nIdx) {
	delete m_nArray[nIdx];
}

bool JuliaBrain::RunTrainingCase(int nIdx) {
	return m_nArray[nIdx]->RunCase(m_pTrainingCaseDB->GetCase(nIdx));
}

float JuliaBrain::RunAllTrainingCase(Complex def) {
	m_pTrainingCaseDB = new CTrainingCaseDB();
	m_pTrainingCaseDB->BuildAllCase();

	float fPassRate = 0;
	int nOkCount = 0;
	bool nResArray[MAX_CASE];

#pragma omp parallel for
	for (int i = 0; i < MAX_CASE; i++) {
		BuildNervusChain(i, def);

		nResArray[i] = RunTrainingCase(i);
		//if (RunTrainingCase(i))
		//	nOkCount++;
		//else
		//	printf("Failed:%d\n", i);
		ReleaseNervusChain(i);
	}

	for (int i = 0; i < MAX_CASE; i++)
		if( nResArray[i] )
			nOkCount++;

	fPassRate = ((float) nOkCount) / MAX_CASE * 100;
	//TRACE( "Passed %d, rate: %f%%\n", nOkCount, fPassRate );

	delete m_pTrainingCaseDB;
	return fPassRate;
}

void JuliaBrain::SetChainDef(int nSigNum, int nNervusNum, int nToNervusNum) {
	m_chDefine[nSigNum].Set(nNervusNum, nToNervusNum);
}

void JuliaBrain::SetOneChainDef(int nChainIdx, int nNervusNum,
		int* pToNervusNum) {
	JuliaChainDefine* pDefine = m_chDefine + NERVUS_SIGNAL_COUNT * nChainIdx;
	for (int i = 1; i < NERVUS_SIGNAL_COUNT; i++) {
		pDefine[i].Set(nNervusNum, pToNervusNum[i - 1]);
	}
}

bool JuliaBrain::LoadChainDefFromFile(int running_id) {
#define BUF_TOTAL_LEN ((NERVUS_COUNT + 2) * (NERVUS_SIGNAL_COUNT - 1) * NERVUS_CHAIN_COUNT)
	char fname[100];
	int buf[BUF_TOTAL_LEN];

	sprintf(fname, "RT_%d.bin", running_id);

	FILE* fNv = fopen(fname, "rb+");
	if (!fNv)
		return false;

	int len = fread(buf, sizeof(int),
			BUF_TOTAL_LEN, fNv);
	fclose(fNv);
	if (len != BUF_TOTAL_LEN)
		return false;

	int *pbuf = buf;

	JuliaChainDefine* pDefine;

	for (int m = 0; m < NERVUS_CHAIN_COUNT; m++) {
		pDefine = m_chDefine + NERVUS_SIGNAL_COUNT * m;
		for (int i = 1; i < NERVUS_SIGNAL_COUNT; i++) {
			int nLen = pDefine[i].Load(pbuf);
			pbuf += nLen;
		}
	}
	return true;
}

void JuliaBrain::SaveChainDefToFile(int running_id) {
	char f_name[100];
	sprintf(f_name, "RT_%d.bin", running_id);
	FILE* f_r = fopen(f_name, "wb+");

	JuliaChainDefine* pDefine;

	for (int m = 0; m < NERVUS_CHAIN_COUNT; m++) {
		pDefine = m_chDefine + NERVUS_SIGNAL_COUNT * m;
		for (int i = 1; i < NERVUS_SIGNAL_COUNT; i++) {
			int buf[NERVUS_COUNT + 2];
			int nLen = pDefine[i].Save(buf);

			fwrite(buf, sizeof(int), nLen, f_r);

		}
	}
	fclose(f_r);
}

void JuliaBrain::PrintChainDef(void) {
	JuliaChainDefine* pDefine;
	for (int m = 0; m < NERVUS_CHAIN_COUNT; m++) {
		pDefine = m_chDefine + NERVUS_SIGNAL_COUNT * m;
		for (int i = 1; i < NERVUS_SIGNAL_COUNT; i++) {
			printf("[%d]%d:", m, i);
			pDefine[i].Print();
		}
	}
}
Complex JuliaBrain::TryTrainingCase(Complex def, int nIdx) {
	Complex rst;
	m_pTrainingCaseDB = new CTrainingCaseDB();
	m_pTrainingCaseDB->BuildAllCase();

	{
		BuildNervusChain(nIdx, def);

		m_nArray[nIdx]->RunCase(m_pTrainingCaseDB->GetCase(nIdx));
		//rst = m_nArray[nIdx]->GetResult();
		ReleaseNervusChain(nIdx);
	}

	delete m_pTrainingCaseDB;
	return rst;
}

void JuliaBrain::TryAllCase(Complex def, double& dMinAngle, double& dMaxAngle) {
	Complex rst;
	m_pTrainingCaseDB = new CTrainingCaseDB();
	m_pTrainingCaseDB->BuildAllCase();
	dMinAngle = 180;
	dMaxAngle = -180;

	for (int i = 0; i < MAX_CASE; i++) {
		BuildNervusChain(i, def);

		m_nArray[i]->RunCase(m_pTrainingCaseDB->GetCase(i));
		//rst = m_nArray[i]->GetResult();
		ReleaseNervusChain(i);

		//printf("%f\n", rst.Angle());
		if (rst.Angle() > dMaxAngle)
			dMaxAngle = rst.Angle();
		if (rst.Angle() < dMinAngle)
			dMinAngle = rst.Angle();
	}

	delete m_pTrainingCaseDB;
}

